package com.agg.persist.provider;


import com.agg.core.base.dto.ExtDTO;
import com.agg.core.exception.EntityMapperException;
import com.agg.core.utils.Asserts;
import com.agg.persist.xml.mapping.EntityMapper;
import com.agg.persist.xml.util.Condition;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.jdbc.SQL;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AbstractSelectTemplateProvider {
    /** 正则匹配 **/
    private final static Pattern HUMP_PATTERN = Pattern.compile("[A-Z]");

    protected String defaultSql( ProviderContext context){
        Class clz=getClass(context);
        String table= getTableName(clz);
        String sqlString = new SQL() {
            {
                SELECT("*");
                FROM(table+" t");
            }
        }.toString();
        return sqlString;

    }

    /**
     * 参数是否有值，拼接条件
     * @param sqlTpl
     * @param em
     * @param t
     * @param extDTO
     * @param <T>
     * @return
     * @throws IllegalAccessException
     */
    protected <T> String getSqlWithCondition(String sqlTpl, EntityMapper em, T t, ExtDTO extDTO)  {
        String sql=sqlTpl+ fillFieldCondtion(em,t);
        if(extDTO!=null){
            List<Condition> conditions= em.getConditions();
            if(Asserts.isNotNullOrEmpty(extDTO.getKeyword())){
                String expression=getExpression("keyword",em);
                if(Asserts.isNotNullOrEmpty(expression)){
                    sql=sql+" and "+expression;
                }
            }
            if(Asserts.isNotNullOrEmpty(extDTO.getStartTime())){
                String expression=getExpression("startTime",em);
                sql=sql+" and "+expression;
            }
            if(Asserts.isNotNullOrEmpty(extDTO.getEndTime())){
                String expression=getExpression("endTime",em);
                sql=sql+" and "+expression;
            }
        }
        return sql;
    }
    /**
     * 参数是否有值，拼接条件
     * @param sqlTpl
     * @param em
     * @param t
     * @param <T>
     * @return
     * @throws IllegalAccessException
     */
    protected <T> String getSqlWithCondition(String sqlTpl, EntityMapper em, T t)  {
        String sql=sqlTpl+ fillFieldCondtion(em,t);
        return sql;
    }


    private <T> String  fillFieldCondtion(EntityMapper em, T t){
        try {
            Field[] fields= t.getClass().getFields();
            StringJoiner joiner=new StringJoiner(" ");
            joiner.add("where");
            for(Field field:fields){
                field.setAccessible(true);
                if(field.get(t)!=null){
                    String key=field.getName();
                    String expression=getExpression(key,em);
                    if(Asserts.isNotNullOrEmpty(expression)){
                        joiner.add(expression);
                    }
                }
            }
            return  joiner.toString();
        }catch (IllegalAccessException  e){
            throw new EntityMapperException("condtion mapper error",e);
        }

    }

    private String getExpression(String key, EntityMapper em){
        List<Condition> conditions= em.getConditions();
        Optional<Condition> optional= conditions.stream().filter(c->c.getKey().contains(key)).findFirst();
        if(optional.isPresent()){
            return  optional.get().getExpression();
        }else{
            return null;
        }
    }


    private Class getClass(ProviderContext context){
        Class mClass = context.getMapperType();
        Type[] types= mClass.getGenericInterfaces();
        ParameterizedType type= (ParameterizedType) (types[0]);
        Type tt=type.getActualTypeArguments()[0];
        return (Class) tt;
    }
    private String getTableName(Class c){
        String className = c.getSimpleName();
        return humpToLine2(className);
    }
    /**
     * 将属性名根据驼峰转换为_连接的列名
     *
     * @param str
     * @return
     */
    private static String humpToLine2(String str) {
        Matcher matcher = HUMP_PATTERN.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        String tableName=sb.toString().replaceFirst("_","");
        return tableName;
    }
}
